package com.wyman.factory.support;

import com.wyman.BeanException;
import com.wyman.PropertyValue;
import com.wyman.PropertyValues;
import com.wyman.factory.config.BeanDefinition;
import com.wyman.factory.config.BeanReference;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;

/**
 * @Author 李伟民
 * @Description DateTime 2024/11/25 01:43
 */
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory{

    private InstantiationStrategy instantiationStrategy = new SimpleInstantiationStrategy();

    @Override
    protected Object createBean(String beanName, BeanDefinition beanDefinition,Object[] args) throws BeanException {

        Object bean;
        //3. 修改真正创建bean的动作
        //bean =  beanDefinition.getBeanClass().newInstance();
        bean = createBeanInstance(beanDefinition,beanName,args);

        //4. 增加给bean的属性赋值
        applyPropertyValues(beanName,bean,beanDefinition);

        //负责管理实例化的bean
        addSingleton(beanName,bean);
        return bean;
    }

    //4.新增
    private void applyPropertyValues(String beanName, Object bean, BeanDefinition beanDefinition) {

        PropertyValues propertyValues = beanDefinition.getPropertyValues();
        Class<?> clazz = beanDefinition.getBeanClass();

        try {
            for (PropertyValue propertyValue : propertyValues.getPropertyValues()) {

                Object value = propertyValue.getValue();
                Field field = clazz.getDeclaredField(propertyValue.getName());
                //用于获取递归拿到的bean对象值
                Object recBean = null;

                //如果属性也是对象 递归实例化
                if(value instanceof BeanReference){
                    recBean = getBean(((BeanReference) value).getBeanName());
                    //使用反射设置属性值 不用工具类
                    field.setAccessible(true);
                    field.set(bean,recBean);

                }
                //如果是基本类型 则直接用value设置值
                else {
                    field.setAccessible(true);
                    field.set(bean,value);
                }

            }
        }
        catch (NoSuchFieldException | IllegalAccessException  e) {
            throw new BeanException("设置Bean属性值失败！"+beanName);
        }
    }

    //根据args找到合适的构造器 调用instantiationStrategy中的实例化方法创建bean
    private Object createBeanInstance(BeanDefinition beanDefinition, String beanName, Object[] args) {

        Object bean = null;

        //空参情况
        if(args==null){
           return instantiationStrategy.instantiate(beanDefinition,beanName,null,null);
        }

        //带参情况
        Class<?> clazz = beanDefinition.getBeanClass();
        for(Constructor ctor:clazz.getDeclaredConstructors()){

           if(ctor.getParameterTypes().length == args.length){
             bean =  getInstantiationStrategy().instantiate(beanDefinition, beanName, ctor, args);
           }
        }

        return bean;
    }

    public InstantiationStrategy getInstantiationStrategy(){
        return this.instantiationStrategy;
    }

    public void setInstantiationStrategy(InstantiationStrategy instantiationStrategy){
        this.instantiationStrategy = instantiationStrategy;
    }

}
